/*****************************************************************/ /**
                                                                     * \file   ModelBuilder.h
                                                                     * \brief   模型创建模块
                                                                     *
                                                                     * \author wangyingjie
                                                                     * \date   March 2025
                                                                     *********************************************************************/

#ifndef MODULEBUILDER_H
#define MODULEBUILDER_H
#include <project_marco.h>

#include <vtkSmartPointer.h>
#include <vtkPoints.h>
#include <vtkCellArray.h>
#include <vtkPolyData.h>

#include <TopExp_Explorer.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <gp_Pnt.hxx>
#include <BRepMesh_IncrementalMesh.hxx>

#include <TopoDS.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Edge.hxx>

#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <Geom_Plane.hxx>

/**
 * @class ModelBuilder
 * @brief 模型创建类
 */
class ModelBuilder
{
  public:
    /**
     * @brief 创建一个梯形
     * @param width 梯形的底边宽度
     * @param height 梯形的高度
     * @param theta 梯形的顶边与底边的夹角（以度为单位）
     * @return 梯形的TopoDS_Shape表示
     */
    static TopoDS_Shape createIsoscelesTrapezoid(const double& width, const double& height, const double& theta)
    {
        // 计算梯形的顶边宽度
        double topWidth = width - 2 * (height * std::tan(theta * M_PI / 180.0));
        if (topWidth < 0)
        {
            std::cerr << "Warning: Invalid trapezoid dimensions." << std::endl;
            topWidth = 0;  // 修正为0
        }
        // 创建梯形的四个顶点
        gp_Pnt p1(-width / 2, 0, 0);
        gp_Pnt p2(width / 2, 0, 0);
        gp_Pnt p3(topWidth / 2, height, 0);
        gp_Pnt p4(-topWidth / 2, height, 0);

        BRepBuilderAPI_MakePolygon polygon;
        polygon.Add(p1);
        polygon.Add(p2);
        polygon.Add(p3);
        polygon.Add(p4);
        polygon.Add(p1);
        polygon.Close();

        // 将多边形转换为面
        TopoDS_Face face = BRepBuilderAPI_MakeFace(polygon.Wire());
        return face;
    }

    /**
     * @brief 指定方向拉伸梯形剖面生成三维形体
     * @param trapezoidProfile 梯形剖面
     * @param direction 拉伸方向和距离
     * @return 拉伸后的三维形体
     */
    static TopoDS_Shape extrude(const TopoDS_Shape& trapezoidProfile, const gp_Vec& direction)
    {
        // 拉伸二维梯形沿指定方向
        //// 拉伸二维梯形沿Z轴
        // BRepPrimAPI_MakePrism prismMaker(trapezoidProfile, direction);
        BRepPrimAPI_MakePrism prismMaker(trapezoidProfile, direction, true);
        return prismMaker.Shape();
    }

    /**
     * @brief 将TopoDS_Shape转换为VTK的PolyData (二维)
     * @param shape 要转换的TopoDS_Shape
     * @return 转换后的VTK PolyData
     */
    static vtkSmartPointer<vtkPolyData> convertToVTK_2(const TopoDS_Shape& shape)
    {
        // 对 TopoDS_Shape 进行三角剖分
        BRepMesh_IncrementalMesh mesh(shape, 0.1);

        // 创建 VTK 的 PolyData
        vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
        vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
        vtkSmartPointer<vtkCellArray> polygons = vtkSmartPointer<vtkCellArray>::New();

        // 遍历 TopoDS_Shape 的每个面
        TopExp_Explorer explorer(shape, TopAbs_FACE);
        for (; explorer.More(); explorer.Next())
        {
            TopoDS_Face face = TopoDS::Face(explorer.Current());
            TopLoc_Location location;
            Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation(face, location);

            if (!triangulation.IsNull())
            {
                // 添加顶点
                for (int i = 1; i <= triangulation->NbNodes(); i++)
                {
                    gp_Pnt point = triangulation->Node(i).Transformed(location.Transformation());
                    points->InsertNextPoint(point.X(), point.Y(), point.Z());
                }

                // 添加面片
                for (int i = 1; i <= triangulation->NbTriangles(); i++)
                {
                    Poly_Triangle triangle = triangulation->Triangle(i);
                    vtkIdType ids[3];
                    ids[0] = triangle.Value(1) - 1;
                    ids[1] = triangle.Value(2) - 1;
                    ids[2] = triangle.Value(3) - 1;
                    polygons->InsertNextCell(3, ids);
                }
            }
        }

        // 打印顶点和面片数量
        std::cout << "Number of points: " << points->GetNumberOfPoints() << std::endl;
        std::cout << "Number of polygons: " << polygons->GetNumberOfCells() << std::endl;

        // 设置 PolyData 的点和面片
        polyData->SetPoints(points);
        polyData->SetPolys(polygons);

        return polyData;
    }

    /**
     * @brief 将OCC的TopoDS_Shape转换为VTK的PolyData (三维)
     * @param shape 要转换的TopoDS_Shape
     * @return 转换后的VTK PolyData
     */
    static vtkSmartPointer<vtkPolyData> convertToVTK_3(const TopoDS_Shape& shape)
    {
        // 对Shape进行三角剖分
        BRepMesh_IncrementalMesh mesh(shape, 0.1);
        vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();           // 存储顶点
        vtkSmartPointer<vtkCellArray> triangles = vtkSmartPointer<vtkCellArray>::New();  // 存储三角形面片
        int pointIndex = 0;
        std::map<int, int> vertexMap;  // Map from OCC index to VTK index

        // 遍历每个面
        TopExp_Explorer faceExplorer(shape, TopAbs_FACE);
        while (faceExplorer.More())  // 遍历所有面
        {
            TopoDS_Face face = TopoDS::Face(faceExplorer.Current());
            TopLoc_Location location;  // 创建局部变量
            Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation(face, location);
            if (!triangulation.IsNull())
            {
                for (int i = 1; i <= triangulation->NbNodes(); ++i)  // 遍历三角剖分中的每个节点（顶点）
                {
                    gp_Pnt p = triangulation->Node(i);
                    // 应用位置变换
                    p.Transform(location.Transformation());
                    points->InsertNextPoint(p.X(), p.Y(), p.Z());
                    vertexMap[i] = pointIndex++;
                }
                for (int i = 1; i <= triangulation->NbTriangles(); ++i)
                {
                    Poly_Triangle triangle = triangulation->Triangle(i);
                    int v1, v2, v3;
                    triangle.Get(v1, v2, v3);
                    vtkIdType ids[3] = {vertexMap[v1], vertexMap[v2], vertexMap[v3]};
                    triangles->InsertNextCell(3, ids);
                }
            }
            faceExplorer.Next();
        }

        std::cout << "Number of points: " << points->GetNumberOfPoints() << std::endl;
        std::cout << "Number of polygons: " << triangles->GetNumberOfCells() << std::endl;

        vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
        polydata->SetPoints(points);
        polydata->SetPolys(triangles);
        return polydata;
    }

    /**
     * @brief 创建等腰梯形(vtk类型的梯形)
     * @param width 梯形的底边宽度
     * @param height 梯形的高度
     * @param theta 梯形的顶边与底边的夹角（以度为单位）
     */
    static vtkSmartPointer<vtkPolyData> createIsoscelesTrapezoid_vtk(double width, double height, double theta)
    {
        // 计算梯形的顶点坐标
        double halfWidth = width / 2;
        double offset = height * std::tan(theta * M_PI / 180.0);

        vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
        points->InsertNextPoint(-halfWidth - offset, 0, 0);  // 左下角
        points->InsertNextPoint(halfWidth + offset, 0, 0);   // 右下角
        points->InsertNextPoint(halfWidth, height, 0);       // 右上角
        points->InsertNextPoint(-halfWidth, height, 0);      // 左上角

        // 定义梯形的拓扑结构（四边形）
        vtkSmartPointer<vtkCellArray> polygons = vtkSmartPointer<vtkCellArray>::New();
        vtkIdType polygon[4] = {0, 1, 2, 3};
        polygons->InsertNextCell(4, polygon);

        // 创建PolyData
        vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
        polyData->SetPoints(points);
        polyData->SetPolys(polygons);

        return polyData;
    }

    /**
     * @brief 检测形状类型
     * @param shape 要检测的形状
     */
    static void CheckShapeType(const TopoDS_Shape& shape)
    {
        switch (shape.ShapeType())
        {
            case TopAbs_VERTEX:
                std::cout << "The shape is a Vertex (Point)." << std::endl;
                break;
            case TopAbs_EDGE:
                std::cout << "The shape is an Edge (Line)." << std::endl;
                break;
            case TopAbs_FACE:
                std::cout << "The shape is a Face." << std::endl;
                break;
            case TopAbs_SHELL:
                std::cout << "The shape is a Shell." << std::endl;
                break;
            case TopAbs_SOLID:
                std::cout << "The shape is a Solid." << std::endl;
                break;
            case TopAbs_COMPOUND:
                std::cout << "The shape is a Compound." << std::endl;
                break;
            default:
                std::cout << "Unknown shape type." << std::endl;
                break;
        }
    }
};

#endif  // MODULEBUILDER_H
